package jvn.client;

import java.io.Serializable;
import java.rmi.RemoteException;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import jvn.client.interfaces.JvnObjectI;
import jvn.client.interfaces.JvnRemoteServerI;
import jvn.client.interfaces.StateI;
import jvn.coord.interfaces.JvnRemoteCoordI;

import org.apache.log4j.Logger;

public class JvnObjectImpl implements JvnObjectI {
	final static private Logger logger = Logger.getLogger(State.class);

	private StateI state;

	private int joi;

	private Serializable object;

	private Lock writeLock = new ReentrantLock();
	private Lock readLock = new ReentrantLock();

	private JvnRemoteCoordI jvnRemoteCoordI;
	private JvnRemoteServerI jvnRemoteServerI;

	public JvnObjectImpl(JvnRemoteCoordI jvnRemoteCoordI, int joiP, JvnRemoteServerI jvnRemoteServerI) {
		this.state = State.initCreate(this);
		this.joi = joiP;
		this.jvnRemoteCoordI = jvnRemoteCoordI;
		this.jvnRemoteServerI = jvnRemoteServerI;
	}

	public JvnObjectImpl(JvnRemoteCoordI jvnRemoteCoordI, JvnObjectI a, JvnServerImpl jvnRemoteServerI) {
		try {
			this.state = State.initLookUp(this);
			this.object = a.jvnGetObjectState();
			this.joi = a.jvnGetObjectId();
		} catch (JvnException e) {
			logger.warn(e);
		}
		this.jvnRemoteCoordI = jvnRemoteCoordI;
		
		this.jvnRemoteServerI = jvnRemoteServerI;
	}

	@Override
	public void jvnLockRead() throws JvnException {
		try {
			logger.debug("LockRead, ancien : " + state);
			state = state.lockRead(this);
			logger.debug("LockRead, nouveau : " + state);
		} catch (RemoteException e) {
			logger.warn(e);
		}
	}

	@Override
	public void jvnLockWrite() throws JvnException {

		try {
			logger.debug("LockWrite, ancien : " + state);
			state = state.lockWrite(this);
			logger.debug("LockWrite, nouveau : " + state);
		} catch (RemoteException e) {
			logger.warn(e);
		}
	}

	@Override
	public void jvnUnLock() throws JvnException {
		try {
			logger.debug("UnLock, ancien : " + state);
			state = state.unlock(this);
			logger.debug("UnLock, nouveau : " + state);
		} catch (RemoteException e) {
			logger.warn(e);
		}
	}

	@Override
	public int jvnGetObjectId() throws JvnException {
		return joi;
	}

	@Override
	public Serializable jvnGetObjectState() throws JvnException {
		return object;
	}

	@Override
	public void jvnInvalidateReader() throws JvnException {
		try {
			logger.debug("InvalidateReader, ancien : " + state);
			state = state.invalidateRead(this);
			logger.debug("InvalidateReader, nouveau : " + state);
		} catch (RemoteException e) {
			logger.warn(e);
		}
	}

	@Override
	public Serializable jvnInvalidateWriter() throws JvnException {
		try {
			logger.debug("InvalidateWriter, ancien : " + state);
			state = state.invalidateWrite(this);
			logger.debug("InvalidateWriter, nouveau : " + state);
		} catch (RemoteException e) {
			logger.warn(e);
		}
		return object;
	}

	@Override
	public Serializable jvnInvalidateWriterForReader() throws JvnException {
		try {
			logger.debug("InvalidateWriterForReader, ancien : " + state);
			state = state.invalidateWriterForReader(this);
			logger.debug("InvalidateWriterForReader, nouveau : " + state);
		} catch (RemoteException e) {
			e.printStackTrace();
		}
		return object;
	}

	@Override
	public void jvnSetObjectState(Serializable state) throws JvnException {
		this.object = state;
	}

	protected void setObject(Serializable object) {
		this.object = object;
	}

	public StateI jvnDebugGetLockState() {
		return state;
	}

	public void jvnDebugSetLockState(StateI state) {
		this.state = state;
	}

	public Lock getReadLock() {
		return readLock;
	}

	public Lock getWriteLock() {
		return writeLock;
	}

	public int getJoi() {
		return joi;
	}

	public JvnRemoteCoordI getJvnRemoteCoord() {
		return jvnRemoteCoordI;
		//return this.jvnServerImpl.getCoord();
	}

	public JvnRemoteServerI getJvnRemoteServer() {
		// passer par le coord.
		return this.jvnRemoteServerI;
	}
}
